<template>
  <div 
  class="rl-select"
  :class="{'is-disabled': disabled }"
  @click="toggleDropdownShow"
  @mouseenter="states.mouseHover = true"
  @mouseleave="states.mouseHover = false"
  >
    <RlTooltip
    placement="bottom-start"
    manual
    ref="tooltipRef"
    :popper-options="popperOptions"
    @click-outside="changeDropdownShow(false)"
    > 
      <!-- 筛选框 -->
      <RlInput
      ref="inputRef"
      v-model="states.inputValue"
      :disabled="disabled"
      :placeholder="filteredPlaceholder"
      :readonly="!filterable"
      @input="debounceOnFilter"
      >
        <template #suffix>
          <RlIcon 
          class="rl-input--clear" 
          v-if="showClearIcon" 
          icon="circle-xmark"
          @click.stop="onClear"
          >
          </RlIcon>
          <RlIcon v-else icon="angle-down" class="rl-select-icon"
          :class="{
            'is-active': isDropdownShow
          }"
          ></RlIcon>
        </template>
        
      </RlInput>
      <!--  选项 -->
      <template #content>
        <!-- loading -->
        <div class="rl-select-loading" v-if="states.loading">
        </div>
        <!-- No Data -->
        <div class="rl-select-nodata" v-if="filterable && filterOptions.length === 0">
        </div>
        <ul class="rl-select-menu" v-else>
          <template v-for="(option, index) in filterOptions" :key="index">
            <li
            class="rl-select-menu-item"
            :class="{'is-disabled': option.disabled, 
            'is-selected': states.selectOption?.value === option.value}"
            :id="`rl-select-menu-item-${option.value}`"
            @click.stop="itemSelect(option)"
            > 
              <RenderVnode :vNode="renderLabel ? renderLabel(option) : option.label"/>
            </li> 
          </template>
        </ul>
      </template>
    </RlTooltip>
  </div>
</template>

<script setup lang="ts">
import type { SelectProps, SelectEmits, SelectOptions, SelectStates } from './types'
import RlInput from '@/components/Input/Input.vue'
import RlTooltip from '@/components/Tooltip/Tooltip.vue'
import type { TooltipInstance } from '@/components/Tooltip/types'
import { ref, reactive, computed, watch } from 'vue'
import type{ Ref } from 'vue'
import RlIcon from '@/components/Icon/Icon.vue'
import RenderVnode from '@/components/RenderVnode'
import { isFunction, debounce } from 'lodash-es'
defineOptions({
  name:'RlSelect'
})
const props = withDefaults(defineProps<SelectProps>(), {
  clearable: false,
  // 设置数组默认值
  options: () => []
})
const tooltipRef = ref() as Ref<TooltipInstance>
const emits = defineEmits<SelectEmits>()
const isDropdownShow = ref(false)
const inputRef = ref()
const timeout = computed((() => props.remote ? 300 : 0))
// 查找对应的option
const findOption = (value: string) => {
  const option = props.options.find(option => option.value === value)
  return option ? option : null
}
const initialOption = findOption(props.modelValue)
const states = reactive<SelectStates>( {
  inputValue: initialOption ? initialOption.label : '',
  selectOption: initialOption,
  mouseHover: false,
  loading: false
})
// eslint-disable-next-line @typescript-eslint/no-explicit-any  
const popperOptions: any = {
  modifiers: [
    {
      name: 'offset',
      options: {
        offset: [0, 9],
      },
    },
    {
      name: "sameWidth",
      enabled: true,
      // eslint-disable-next-line @typescript-eslint/no-explicit-any
      fn: ({ state }: { state: any }) => {
          state.styles.popper.width = `${state.rects.reference.width}px`;
      },
      phase: "beforeWrite",
      requires: ["computeStyles"],
    }
  ],
}
const filterOptions = ref(props.options)
watch(() => props.options, (newOptions) => {
  filterOptions.value = newOptions
})
const generateFilterOptions = async (searchValue: string) => {
  if (!props.filterable) return
  if (props.filterMethod && isFunction(props.filterMethod)) {
    filterOptions.value = props.filterMethod(searchValue)
  } else if(props.remote && props.remoteMethod && isFunction(props.remoteMethod)) {
    states.loading = true
    try {
      // 远程请求支持防抖
      filterOptions.value = await props.remoteMethod(searchValue)
    } catch(e) {
      console.error(e)
      filterOptions.value = []
    } finally {
      states.loading = false
    }
  }
  else { // 默认过滤规则
    filterOptions.value = props.options.filter(option => option.label.includes(searchValue))
  }
}
const onFilter = () => {
  generateFilterOptions(states.inputValue)
}
const debounceOnFilter = debounce(() => {
  onFilter()
}, timeout.value)

const changeDropdownShow = (show: boolean) => {
  if (show) {
    // 如果是filter并且之前有值
    if (props.filterable && states.selectOption) {
      states.inputValue = ''
    }
    if (props.filterable) {
      // 默认选项的生成
      generateFilterOptions(states.inputValue)
    }
    tooltipRef.value.show()
  } else {
    tooltipRef.value.hide()
    if (props.clearable) {
      states.inputValue = states.selectOption ? states.selectOption.label : ''
    }
  }
  isDropdownShow.value = show
  emits('visible-change', show)
}
const toggleDropdownShow = () => {
  if (props.disabled) return
  if (isDropdownShow.value) {
    changeDropdownShow(false)
  } else {
    changeDropdownShow(true)
  }
}
const itemSelect = (e: SelectOptions) => {
  if (e.disabled) return
  // inputValue.value = e.label
  states.inputValue = e.label
  states.selectOption = e
  emits('change', e.value)
  emits('update:modelValue', e.value)
  changeDropdownShow(false)
  // inputRef.value.ref.focus()
}
const showClearIcon = computed(() => {
  // hover clearable inputValue 
  return props.clearable && states.mouseHover && states.selectOption && states.inputValue.trim() !== ''
})
const filteredPlaceholder = computed(() => {
  if (props.filterable && states.selectOption && isDropdownShow.value) {
    return states.selectOption.label
  } else {
    return props.placeholder
  }
})
const onClear = () => {
  states.inputValue = ''
  states.selectOption = null
  emits('clear')
  emits('change', '')
  emits('update:modelValue', '')
}
</script>